#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>


using namespace std;
class ZeroEvenOdd {
private:
    int n;
    int flag;
    int cur;
    std::mutex mtx;
    condition_variable cv;

public:
    ZeroEvenOdd(int n) {
        this->n = n;
        flag = 1;
        cur = 1;
    }

    // printNumber(x) outputs "x", where x is an integer.
    void zero(function<void(int)> printNumber) {
        
        for(int i = 1;i <= n;i++)
        {
            unique_lock<std::mutex> lock(mtx);
            cv.wait(lock,[this](){return flag == 1;});
            printNumber(0);
            flag = ((cur % 2) == 0) ? 2 : 3;
            cv.notify_all();
        }
        
    }

    void even(function<void(int)> printNumber) {
       
        for(int i = 2;i <=n;i += 2)
        {
             unique_lock<std::mutex> lock(mtx);
            cv.wait(lock,[this](){return flag == 2;});
            
            printNumber(cur);
            flag = 1;
            cur++;
            cv.notify_all();
            
        }
    }

    void odd(function<void(int)> printNumber) {
        
        for(int i = 1;i <= n;i += 2)
        {
            unique_lock<std::mutex> lock(mtx);
            cv.wait(lock,[this](){return flag == 3 ;});
           
                printNumber(cur);
                flag = 1;
                cur++;
                cv.notify_all();
            
        }
    }
};

int main()
{
    ZeroEvenOdd zeo(9);

    auto print = [](int x){cout << x ;};
    thread t1(&ZeroEvenOdd::zero,&zeo,print);
    thread t2(&ZeroEvenOdd::even,&zeo,print);
    thread t3(&ZeroEvenOdd::odd,&zeo,print);

    t1.join();
    t2.join();
    t3.join();

}